Option Explicit

' ======================================================================
' Descriptor
' 二元条件对象
' ======================================================================

' ======================================================================
' Implement
' ======================================================================

Implements ISqlFormatterCondition
Implements ISqlFormatterElem
Implements ISqlFormatterAlignmentElem

' ======================================================================
' Field
' ======================================================================
' ==================================================
' Field
' ==================================================
' 组成条件的所有元素
' 默认情况下的组成内容为: and a = b 一共 4 各元素，这里扩充为两倍
' IObjArrayRef<ISqlFormatterElem>
Private componentArray As IObjArrayRef

' 缓存: 逻辑运算符的索引位置
' 如果是 -1，则说明当前条件中没有逻辑运算符
Private logicOperatorIndex As Long

' 缓存: 条件运算符的索引位置
' 如果是 -1，则说明当前条件中没有条件运算符
Private conditionOperatorIndex As Long

' 条件运算符左侧是不是多行的状态
' 默认值 = false
Private leftMultiLineState As Boolean

' 条件运算符左侧列对象部分是不是多行(这里需要忽略开头部分的注释，只关心列对象本身)
' 0 = 现在左侧都是注释 token 或者还没有出现非注释列对象
' 1 = 左侧出现了列对象，但仍然是单行状态
' 2 = 左侧出现了列对象，已经是多行的状态了。有可能是因为出现了多行列对象，也有可能是因为两个列对象之间出现了注释
'     如果是: 单行列元素 + 一个以注释结尾的单行内容 + 条件运算符，这种情况也要设置为多行状态
'            虽然是条件运算符左侧是单行状态，但是因为是以注释结尾的所以无法再连接其他内容，所以设置为多行状态
'            并且舍弃这种情况下的右侧元素对齐
' 默认值 = 0
Private leftElemIsMultiLine As Byte

' 条件运算符右侧侧是不是多行的状态
' 默认值 = false
Private rightMultiLineState As Boolean

' 元素数组是否是以注释结尾
' 默认值 = false
Private componentArrayIsEndsWithComment As Boolean

' ==================================================
' ISqlFormatterElem -- Field
' ==================================================
' 左侧括号的数量
' 默认值 = 0
Private leftParenthesisCount As Integer
' 右侧括号的数量
' 默认值 = 0
private rightParenthesisCount As Integer

' ==================================================
' ISqlFormatterCondition -- Field
' ==================================================
' 当前条件是不是其所在区域的唯一条件对象
' 默认值 = true
Private isOnlyOneCondition As Boolean

' 前缀空格数量
Private prefixSpaceCount As Integer

' 对齐空格数量
' 默认值 = 0
Private alignmentSpaceCount As Integer

' 初始对齐长度
Private alignmentSize As Integer

' ==================================================
' private cache -- Field
' 这里的全部字段用来在计算对齐长度时，提前生成部分字符串时，缓存生成结果
' ==================================================
' 缓存原始字符串集合
' ！！！！！完整的原始字符串集合生成完成之后，需要主动清空！！！！！
' IPrimitiveArrayRef<String>
Private cacheOriginStrArray As IPrimitiveArrayRef

' ======================================================================
' Constructor
' ======================================================================
Private Sub Class_Initialize()
    ' 组成条件的所有元素
    Set componentArray = UtilsArrayRef.createRealObjArrayRef(8)

    ' 缓存: 逻辑运算符的索引位置
    logicOperatorIndex = -1

    ' 缓存: 条件运算符的索引位置
    conditionOperatorIndex = -1

    ' 当前条件是不是其所在区域的唯一条件对象
    isOnlyOneCondition = True

    ' 初始对齐长度
    alignmentSize = -1
End Sub

Private Sub Class_Terminate()
    Set componentArray = Nothing
    Set cacheOriginStrArray = Nothing
End Sub


' ======================================================================
' implements ISqlFormatterAlignmentElem Function
' ======================================================================
' ==================================================
' ISqlFormatterAlignmentElem -- 获取、设置对齐长度
' ==================================================
' 返回对齐的长度:
'     前缀空格数量 + 逻辑运算符长度(如果有) + 第一运算元素长度 + 条件运算符的长度 + 分隔符空格数量
' 如果当前对象无法对齐，将会返回 -1
Public Function ISqlFormatterAlignmentElem_getAlignmentSize(ByRef config As SqlFormatterConfiguration) As Integer
    ' ==================================================
    ' 1. 快速结束
    ' ==================================================
    ' 1. 检查: 如果条件运算符不存在 `conditionOperatorIndex == -1`，则退出，并返回 `-1`
    If conditionOperatorIndex = -1 Then
        ' return -1
        ISqlFormatterAlignmentElem_getAlignmentSize = -1
        Exit Function
    End If


    ' 2. 检查: 如果条件运算符左侧不存在列对象 `leftElemIsMultiLine == 0`，则退出，并返回 `-1`
    If leftElemIsMultiLine = 0 Then
        ' return -1
        ISqlFormatterAlignmentElem_getAlignmentSize = -1
        Exit Function
    End If

    ' 3. 检查: 如果已经计算完了 `alignmentSize != -1`，则直接返回属性 `alignmentSize`
    If alignmentSize <> -1 Then
        ' return alignmentSize
        ISqlFormatterAlignmentElem_getAlignmentSize = alignmentSize
        Exit Function
    End If

    ' 4. 检查: 如果左侧列元素是多行，则退出处理，并返回 `-1`
    If leftElemIsMultiLine = 2 Then
        ' return -1
        ISqlFormatterAlignmentElem_getAlignmentSize = -1
        Exit Function
    End If

    ' ==================================================
    ' 2. 初始化
    ' ==================================================
    ' 1. 如果左侧是单行的 ，则设置: `alignmentSize = 1`
    '    这里的 1 表示元素连接的字符串和条件运算符之间的那个空格
    '    无论是多行还是单行都需要有一个空格
    alignmentSize = 1

    ' ==================================================
    ' 3. 处理开头的填充空格
    ' ==================================================
    ' 1. 检查: 如果需要开头的填充空格，则设置 `alignmentSize += 4`
    If needStartFillSpace(config) Then
        alignmentSize = alignmentSize + 4
    End If

    ' ==================================================
    ' 4. 处理左侧元素
    ' ==================================================
    ' 1. 获取条件运算符左侧元素的字符串长度，并累加到 `alignmentSize`
    alignmentSize = alignmentSize + getConditionOpLeftStrLen(config)

    ' ==================================================
    ' 5. 按照对齐的类型处理条件运算符
    ' ==================================================
    ' 1. 检查: 如果配置的对齐方式是条件运算符右侧对齐，则继续
    If config.alignmentPosition = SqlAlignmentPosition.OPERATOR_RIGHT Then
        ' 2. 获取条件运算符的长度，并累加到 `alignmentSize`
        alignmentSize = alignmentSize + getConditionOpStrLen(config)
    End IF

    ' ==================================================
    ' 6. 处理前缀空格长度
    ' ==================================================
    ' 1. 累计前缀空格长度 `prefixSpaceCount`，结果保存到 `alignmentSize`
    alignmentSize = alignmentSize + prefixSpaceCount

    ' ==================================================
    ' 7. 退出处理，返回属性 `alignmentSize`
    ' ==================================================
    ' return alignmentSize
    ISqlFormatterAlignmentElem_getAlignmentSize = alignmentSize
End Function

' 设置对齐空格长度
Public Sub ISqlFormatterAlignmentElem_setAlignmentSpaceCount(ByVal count As Integer, ByRef config As SqlFormatterConfiguration)
    ' ==================================================
    ' 1. 保存对齐空格的长度
    ' ==================================================
    alignmentSpaceCount = count

    ' ==================================================
    ' 2. 检查: 如果不存在条件运算符 `conditionOperatorIndex == -1`，则退出处理
    ' ==================================================
    If conditionOperatorIndex = -1 Then
        ' return
        Exit Sub
    End If

    ' ==================================================
    ' 3. 检查: 如果条件运算符左侧不存在列对象 `leftElemIsMultiLine == 0`，则退出处理
    ' ==================================================
    If leftElemIsMultiLine = 0 Then
        ' return
        Exit Sub
    End If

    ' ==================================================
    ' 3. 遍历设置条件运算符右侧的元素
    ' ==================================================
    ' 1. 计算条件运算符右侧元素的前缀空格长度，结果保存到变量 `rightElemPrefixSpaceCount`
    Dim rightElemPrefixSpaceCount As Integer
    rightElemPrefixSpaceCount = getConditionOpRightElemPrefixSpaceCount(config)

    ' 2. 从 `i = conditionOperatorIndex + 1` 开始遍历到 `componentArray.MaxIndex`
    Dim component As ISqlFormatterElem
    Dim i As Long
    For i = conditionOperatorIndex + 1 To componentArray.MaxIndex
        ' 3. 获取第 i 个元素到 `componentArray`
        Set component = componentArray.Item(i)

        ' 4. 设置元素的前缀空格数量为 `rightElemPrefixSpaceCount`
        component.setPrefixSpaceCount rightElemPrefixSpaceCount , config

        ' 5. 从 3 进入下一轮遍历
    Next
End Sub

' ==================================================
' 获取元素
' ==================================================
' 从条件的左侧元素获取条件组
' 如果没有条件组，则应该返回 null
' @reutrn IObjArrayRef<IObjArrayRef<ISqlFormatterAlignmentElem>>
Public Function ISqlFormatterAlignmentElem_getAlignmentElemGroupsFromLeftElem() As IObjArrayRef
    ' ==================================================
    ' 1. 声明变量
    ' ==================================================
    ' 1. 结束索引 `long endIndex`
    Dim endIndex As Long

    ' ==================================================
    ' 2. 确认结束索引
    ' ==================================================
    ' 1. 检查: 如果不存在条件运算符，则设置 `endIndex = componentArray.MaxIndex`
    If conditionOperatorIndex = -1 Then
        endIndex = componentArray.MaxIndex

    ' 2. 否则，设置 `endIndex = conditionOperatorIndex - 1`
    Else
        endIndex = conditionOperatorIndex - 1
    End If

    ' ==================================================
    ' 3. 生成结果
    ' ==================================================
    ' 1. 执行: 从一组元素中获取条件组
    Set ISqlFormatterAlignmentElem_getAlignmentElemGroupsFromLeftElem = doGetConditionGroupFromComponents(0, endIndex)
End Function

' 从条件的右侧元素获取条件组
' 如果没有条件组，则应该返回 null
' @return IObjArrayRef<IObjArrayRef<ISqlFormatterAlignmentElem>>
Public Function ISqlFormatterAlignmentElem_getAlignmentElemGroupsFromRightElem() As IObjArrayRef
    ' ==================================================
    ' 1. 快速结束
    ' ==================================================
    ' 1. 检查: 如果不存在条件运算符，则退出处理，返回 `null`
    If conditionOperatorIndex = -1 Then
        ' return null
        Exit Function
    End If

    ' ==================================================
    ' 2. 生成结果
    ' ==================================================
    ' 1. 执行: 从一组元素中获取条件组
    Set ISqlFormatterAlignmentElem_getAlignmentElemGroupsFromRightElem = doGetConditionGroupFromComponents(conditionOperatorIndex + 1, componentArray.MaxIndex)
End Function

' ======================================================================
' implements ISqlFormatterCondition Function
' ======================================================================

' ==================================================
' 当前条件的运算符
' ==================================================
' 添加当前条件的逻辑运算符
' 对于每个表级作用域 + 片段级作用域where条件中的第一个条件是没有逻辑运算符的
Public Sub ISqlFormatterCondition_setLogicOperator(ByRef t As SqlToken)
    If t Is Nothing Then
        Exit Sub
    End If

    ' 保存逻辑运算符
    componentArray.Add t

    ' 保存: 逻辑运算符的索引位置
    logicOperatorIndex = componentArray.MaxIndex

    ' 如果前一个元素是注释结尾，则设置左侧为多行状态
    If componentArrayIsEndsWithComment Then
        leftMultiLineState = True
    End If

    ' 重置: 最后一个元素不是以注释结尾
    componentArrayIsEndsWithComment = False

    ' 重置: 条件运算符左侧列对象的多行状态 = 0
    '       因为出现了逻辑运算符，那么在逻辑运算符之前的状态就可以忽略了，
    '       只要【逻辑运算符】后到【条件运算符】前的状态
    leftElemIsMultiLine = 0
End Sub

' 设置条件运算符
' 参数类型有可能是 SqlToken 或 SqlFormatterTokenGroup
Public Sub ISqlFormatterCondition_setConditionOperator(ByRef t As ISqlFormatterElem)
    If t Is Nothing Then
        Exit Sub
    End If

    ' 保存条件运算符
    componentArray.Add t

    ' 保存: 条件运算符的索引位置
    conditionOperatorIndex = componentArray.MaxIndex

    ' 如果前一个元素是注释结尾，则设置左侧为多行状态
    If componentArrayIsEndsWithComment Then
        leftMultiLineState = True

        leftElemIsMultiLine = 2
    End If

    ' 重置: 最后一个元素不是以注释结尾
    componentArrayIsEndsWithComment = false
End Sub

' ==================================================
' 其他
' ==================================================
' 设置当前条件不是整个区域中的唯一一个条件
' 用来取消只有一个条件时，因为配置 firstConditionNeedFillSpace = true 而产生的额外前缀空格
' 在解析 sql 时，如果只有一个条件对象，则有可能不会被复合条件对象包装，这会导致无法设置这个条件对象的唯一性。所以，这里改为设置条件对象的 [非唯一性]
' 在初始化时，默认设置为唯一条件，这样即使不被复合条件对象包装，也可以被识别为唯一条件
' 在复合条件对象内，遇到多个条件对象时，可以主动设置每一个条件对象的非唯一性
Public Sub ISqlFormatterCondition_setNotOnlyOneCondition()
    isOnlyOneCondition = false
End Sub

' ======================================================================
' implements ISqlFormatterElem Function
' ======================================================================
' ==================================================
' ISqlFormatterElem -- 添加组成元素
' ==================================================
' 添加组成元素
Public Sub ISqlFormatterElem_addComponent(ByRef c As ISqlFormatterElem)
    ' ==================================================
    ' 1. 参数检查
    ' ==================================================
    ' 1. 检查: 如果元素是 `null` 则退出
    If c Is Nothing Then
        ' return
        Exit Sub
    End If

    ' ==================================================
    ' 2. 保存元素
    ' ==================================================
    ' 1. 将元素保存到元素数组中
    componentArray.Add c

    With c ' ------> 在这里加速
        ' ==================================================
        ' 3. 元素记录到右侧
        ' ==================================================
        ' 1. 检查: 如果条件运算符的索引已存在: `conditionOperatorIndex != -1` (检查结果需要记录到右侧)
        If conditionOperatorIndex <> -1 Then
            ' 2. 检查: 如果右侧不是多行状态 `rightMultiLineState == false`，则继续
            If rightMultiLineState = False Then
                ' 3. 检查: 如果当前元素是多行的，则设置 `rightMultiLineState = true`
                If .isMultiLine Then
                    rightMultiLineState = true

                ' 4. 否则，检查: 如果元素数组是以注释结尾的，则设置 `rightMultiLineState = true`
                ElseIf componentArrayIsEndsWithComment Then
                    rightMultiLineState = True

                ' 5. 否则，检查: 如果当前元素是单独一行的注释，则设置 `rightMultiLineState = true`
                ElseIf .isSingleLineComment Then
                    rightMultiLineState = True
                End If
            End If

        ' ==================================================
        ' 4. 元素记录到左侧
        ' ==================================================
        ' 1. 否则(接 3 的判断)，记录到左侧
        else
            ' 2. 检查: 如果左侧不是多行状态 `leftMultiLineState == false`，则继续
            If leftMultiLineState = false Then
                ' 3. 检查: 如果当前元素是多行的，则设置 `leftMultiLineState = true`
                If .isMultiLine Then
                    leftMultiLineState = True

                ' 4. 否则，检查: 如果元素数组是以注释结尾的，则设置 `leftMultiLineState = true`
                ElseIf componentArrayIsEndsWithComment Then
                    leftMultiLineState = True

                ' 5. 否则，检查: 如果当前元素是单独一行的注释
                ElseIf .isSingleLineComment Then
                    ' 5.1. 如果元素数组中的元素数量 > 1 ，则设置 `leftMultiLineState = true`
                    If componentArray.Count > 1 Then
                        leftMultiLineState = True
                    End If
                End IF
            End If

            ' 6. 记录条件运算符左侧列对象的多行状态
            ' 6.1. 检查: 如果左侧还没有列对象: `leftElemIsMultiLine == 0`
            If leftElemIsMultiLine = 0 Then
                ' 6.1.1. 检查: 如果当前元素不是注释，则继续: `isComment() == false`
                If .isComment = False Then
                    ' 6.1.2. 检查: 如果当前元素是多行的，设置 `leftElemIsMultiLine == 2`
                    If .isMultiLine Then
                        leftElemIsMultiLine = 2

                    ' 6.1.3. 否则(当前元素是单行的)，设置 `leftElemIsMultiLine == 2`
                    Else
                        leftElemIsMultiLine = 1
                    End If
                End If

            ' 6.2. 否则，检查: 如果左侧列对象是单行的: `leftElemIsMultiLine == 1`
            ElseIf leftElemIsMultiLine = 1 Then
                ' 6.2.1. 检查: 如果元素数组是以注释结尾的，则设置 `leftElemIsMultiLine == 2`
                If componentArrayIsEndsWithComment Then
                    leftElemIsMultiLine = 2

                ' 2. 否则，检查: 如果当前元素是多行的，则设置 `leftElemIsMultiLine == 2`
                ElseIf .isMultiLine Then
                    leftElemIsMultiLine = 2
                End If
            End If
        End If

        ' ==================================================
        ' 5. 将当前元素的是否以注释结尾的结果: `isEndsWithComment() == true` 保存到属性 `componentArrayIsEndsWithComment`
        ' ==================================================
        componentArrayIsEndsWithComment = (.isEndsWithComment = True)
    End With
End Sub

' 将元素添加到开头位置
Public Sub ISqlFormatterElem_addComponentToFirst(ByRef c As ISqlFormatterElem)
    ' ==================================================
    ' 1. 参数检查
    ' ==================================================
    ' 1. 检查: 如果元素是 `null` 则退出
    If c Is Nothing Then
        ' return
        Exit Sub
    End If

    With c ' ------> 在这里加速
        ' ==================================================
        ' 2. 保存元素
        ' ==================================================
        ' 1. 将元素添加到开头位置
        componentArray.AddFirst c

        ' 2. 获取元素数量 和 当前元素是否是以注释结尾
        Dim componentArrayCount As Long
        componentArrayCount = componentArray.Count

        Dim curIsEndsWithComment As Boolean
        curIsEndsWithComment = .isEndsWithComment

        ' 索引缓存位置向后移动
        ' 缓存: 逻辑运算符的索引位置
        If logicOperatorIndex <> -1 Then
            logicOperatorIndex = logicOperatorIndex + 1
        End If

        ' 缓存: 条件运算符的索引位置
        If conditionOperatorIndex <> -1 Then
            conditionOperatorIndex = conditionOperatorIndex + 1
        End If

        ' ==================================================
        ' 3. 元素记录到左侧
        ' ==================================================
        ' 在这个方法中
        ' 如果已经有了条件运算符，那么应该将元素记录到左侧
        ' 如果还没有条件运算符，还是需要将元素记录到左侧
        ' 所以这里只需要做元素记录到左侧的情况即可
        ' 1. 检查: 如果左侧不是多行的状态 `leftMultiLineState == false`，则继续
        If leftMultiLineState = False Then
            ' 2. 检查: 如果当前元素是多行的，则设置 `leftMultiLineState = true`，并结束
            If .isMultiLine Then
                leftMultiLineState = True
            ' 3. 否则，检查: 如果元素数量 > 1
            ElseIf componentArrayCount > 1 Then
                ' 3.1. 检查: 如果当前元素是注释结尾，则是多行
                '    (说明在单行的基础行，又增加了一个包含注释的内容，所以变成了多行)
                If curIsEndsWithComment Then
                    leftMultiLineState = True

                ' 3.2. 否则，检查: 如果第二个元素是单行注释，则设置为多行的
                Else
                    Dim tempElem As ISqlFormatterElem
                    Set tempElem = componentArray.Item(1)
                    If tempElem.isSingleLineComment Then
                        leftMultiLineState = True
                    End If
                End If
            End If
            ' 4. 否则 (到这里说明只有一个元素，则不用检查，无论是哪种情况都是单行的)
        End If

        ' ==================================================
        ' 4. 记录条件运算符左侧列对象的多行状态
        ' ==================================================
        ' 1. 如果不存在逻辑运算符，则继续: `logicOperatorIndex = -1`
        If logicOperatorIndex = -1 Then
            ' 2. 检查: 如果当前元素不是是注释，则继续
            If .isComment = False Then
                ' 3. 检查: 如果左侧还没有列对象，则设置 `leftElemIsMultiLine == 1`: `leftElemIsMultiLine == 0`
                If leftElemIsMultiLine = 0 Then
                    leftElemIsMultiLine = 1

                ' 4. 否则，检查: 如果左侧列对象是单行的: `leftElemIsMultiLine == 1`
                ElseIf leftElemIsMultiLine = 1 Then
                    ' 4.1 检查: 如果当前元素是以注释结尾的
                    If curIsEndsWithComment Then
                        ' 4.1.1 检查: 如果元素数组的数量 > 1，则设置 `leftElemIsMultiLine == 2`
                        If componentArrayCount > 1 Then
                            leftElemIsMultiLine = 2
                        End If

                    ' 4.2 否则，检查: 如果当前元素是多行的，则设置 `leftElemIsMultiLine == 2`
                    ElseIf .isMultiLine Then
                        leftElemIsMultiLine = 2

                    ' 4.3 否则（这是一个单行元素）
                    Else
                        ' 4.3.1 如果元素数组的数量 > 1，则继续
                        If componentArrayCount > 1 Then
                            ' 4.3.2 获取第 2 个元素，保存到 `ISqlFormatterElem elem`
                            Dim elem As ISqlFormatterElem
                            Set elem = componentArray.Item(1)
                            ' 4.3.3 检查: 如果第 2 个元素是单行注释，则设置 `leftElemIsMultiLine == 2`: `isSingleLineComment()`
                            If elem.isSingleLineComment Then
                                leftElemIsMultiLine = 2

                            ' 4.3.3 否则，检查: 如果第 2 个元素是同行注释 + 元素数组的数量 > 2，则设置 `leftElemIsMultiLine == 2`
                            ElseIf elem.isShareLineComment And componentArrayCount > 2 Then
                                leftElemIsMultiLine = 2
                            End If
                        End If
                    End If
                End If
            End If
        End If

        ' ==================================================
        ' 5. 如果当前只有一个元素，则保存: 是否是以注释结尾
        ' ==================================================
        If componentArrayCount = 1 Then
            componentArrayIsEndsWithComment = curIsEndsWithComment
        End If
    End With
End Sub

' 能否将元素添加到开头位置
Public Function ISqlFormatterElem_canAddComponentToFirst() As Boolean
    ' 不存在左边界括号时，可以将元素添加到开头
    ISqlFormatterElem_canAddComponentToFirst = (leftParenthesisCount <= 0)
End Function

' ==================================================
' ISqlFormatterElem -- 对齐处理
' ==================================================
' 该方法是用来配置对齐的方法
' 返回元素内，最多一级深度下的对齐元素组
' 如果是列对象，则返回作用域各个组成元素内的条件组（主要是子查询）
' 如果是条件对象，则返回条件自身
' 如果是作用域对象，则返回作用域内各部分中的条件组合
' 如果是赋值语句，则返回语句自身
' 如果没有条件或者赋值语句，则返回 null
'
' @return IObjArrayRef<IObjArrayRef<ISqlFormatterAlignmentElem>>
Public Function ISqlFormatterElem_getAlignmentElemGroups() As IObjArrayRef
    ' 这里直接返回自身
    Set ISqlFormatterElem_getAlignmentElemGroups = UtilsArrayRef.wrapperToObjArrayRef(UtilsArrayRef.wrapperToObjArrayRef(Me))
End Function

' ==================================================
' ISqlFormatterElem -- 前缀空格设置
' ==================================================
' 设置当前元素的嵌套深度，并计算前缀空格的数量
' 会覆盖 setPrefixSpaceCount 的设置结果
Public Sub ISqlFormatterElem_setElemNestCount(ByVal nestCount As Integer, ByRef config As SqlFormatterConfiguration)
    ' 1. 按照元素嵌套深度计算前缀空格数量
    Dim spaceCount As Integer
    spaceCount = nestCount * config.elemNestLevelPrefixSpaceCount

    ' 2. 执行: 设置元素前缀空格的流程
    ISqlFormatterElem_setPrefixSpaceCount spaceCount, config
End Sub

' 直接设置前缀空格的数量
' 将会覆盖 setElemNestCount 对前缀空格数量的控制
Public Sub ISqlFormatterElem_setPrefixSpaceCount(ByVal spaceCount As Integer, ByRef config As SqlFormatterConfiguration)
    ' ==================================================
    ' 1. 保存当前条件的前缀空格数量
    ' ==================================================
    prefixSpaceCount = spaceCount

    ' ==================================================
    ' 2. 声明变量
    ' ==================================================
    ' 1. 条件内元素的前缀空格的数量 `int subElemPrefixSpaceCount`
    Dim subElemPrefixSpaceCount As Integer
    ' 2. 遍历索引 `long i`
    Dim i As Long
    ' 3. 遍历结束索引 `long endIndex`
    Dim endIndex As Long
    ' 4. 元素 `ISqlFormatterElem component`
    Dim component As ISqlFormatterElem

    ' ==================================================
    ' 3. 遍历设置条件运算符左侧的元素
    ' ==================================================
    ' 1. 计算条件运算符左侧元素的前缀空格长度，结果保存到 `subElemPrefixSpaceCount`
    subElemPrefixSpaceCount = getConditionOpLeftElemPrefixSpaceCount(config)

    ' 2. 确认遍历的结束位置 `endIndex`
    ' 2.1. 如果当前条件不存在条件运算符 `conditionOperatorIndex == -1`，设置 `endIndex = componentArray.MaxIndex`
    If conditionOperatorIndex = -1 Then
        endIndex = componentArray.MaxIndex

    ' 2.2. 否则，设置为 `endIndex = conditionOperatorIndex - 1`
    Else
        endIndex = conditionOperatorIndex - 1
    End If

    ' 3. 从 `i = 0` 开始遍历到 `endIndex`
    For i = 0 To endIndex
        ' 4. 获取第 i 个元素到 `component`
        Set component = componentArray.Item(i)
        ' 5. 设置元素的前缀空格数量为 `subElemPrefixSpaceCount`
        component.setPrefixSpaceCount subElemPrefixSpaceCount, config
        ' 6. 从 4 开始进入下一轮遍历
    Next

    ' ==================================================
    ' 4. 遍历设置条件运算符右侧的元素
    ' ==================================================
    ' 1. 检查: 如果不存在条件运算符 `conditionOperatorIndex == -1`，则退出处理
    If conditionOperatorIndex = -1 Then
        ' return
        Exit Sub
    End If

    ' 2. 检查: 如果存在对齐操作，则退出处理
    '    有对齐的情况下，在这里退出，之后会在做对齐时，通过: 设置对齐空格的长度--setAlignmentSpaceCount 方法来设置
    If config.alignmentLevel <> SqlAlignmentLevel.NO_ALIGNMENT Then
        ' return
        Exit Sub
    End If

    ' 3. 计算条件运算符右侧元素的前缀空格长度
    subElemPrefixSpaceCount = getConditionOpRightElemPrefixSpaceCount(config)

    ' 4. 从 `i = conditionOperatorIndex + 1` 开始遍历到 `endIndex = componentArray.MaxIndex`
    For i = conditionOperatorIndex + 1 To componentArray.MaxIndex
        ' 5. 获取第 i 个元素到 `component`
        Set component = componentArray.Item(i)
        ' 8. 设置元素的前缀空格数量为 `subElemPrefixSpaceCount`
        component.setPrefixSpaceCount subElemPrefixSpaceCount, config
        ' 9. 从 5 进入下一轮遍历
    Next
End Sub

' ==================================================
' ISqlFormatterElem -- 边界括号
' ==================================================
' 是否存在边界括号，有左边或者右边都返回 true
Public Function ISqlFormatterElem_hasBoundaryParenthesis() As Boolean
    If leftParenthesisCount > 0 Then
        ISqlFormatterElem_hasBoundaryParenthesis = True
    ElseIf rightParenthesisCount > 0 Then
        ISqlFormatterElem_hasBoundaryParenthesis = True
    End If

    ' return false
End Function

' 边界处的 [(] 的数量 + count 个
Public Sub ISqlFormatterElem_addBoundaryLeftParenthesis(Optional ByVal count As Integer = 1)
    leftParenthesisCount = leftParenthesisCount + count
End Sub

' 边界处的 [)] 的数量 + count 个
Public Sub ISqlFormatterElem_addBoundaryRightParenthesis(Optional ByVal count As Integer = 1)
    rightParenthesisCount = rightParenthesisCount + count
End Sub

' ==================================================
' ISqlFormatterElem -- 内容检查
' ==================================================
' 获取类型
Public Function ISqlFormatterElem_getType() As SqlTokenType
    ISqlFormatterElem_getType = SqlTokenType.NO_MEAN
End Function

' 检查当前元素是不是一个注释
Public Function ISqlFormatterElem_isComment() As Boolean
    ' return false
End Function

' 检查当前元素是不是和前一个元素处于同一行的注释
Public Function ISqlFormatterElem_isShareLineComment() As Boolean
    ' return false
End Function

' 检查当前元素是不是处于单独一行的注释
Public Function ISqlFormatterElem_isSingleLineComment() As Boolean
    ' return false
End Function

' 检查当前元素是不是以注释结尾
Public Function ISqlFormatterElem_isEndsWithComment() As Boolean
    ' 1. 如果存在右括号，则默认不是以注释结尾
    If rightParenthesisCount > 0 Then
        ' return false
        Exit Function
    End If

    ' 2. 返回元素数组是否以注释结尾
    ISqlFormatterElem_isEndsWithComment = componentArrayIsEndsWithComment
End Function

' 检查当前生成器是不是多行的
Public Function ISqlFormatterElem_isMultiLine() As Boolean
    ' 1. 检查: 如果左侧的元素是多行的 `leftMultiLineState == true`，则返回 `true`
    If leftMultiLineState Then
        ' return true
        ISqlFormatterElem_isMultiLine = True
        Exit Function
    End If

    ' 2. 检查: 如果右侧的元素是多行的 `rightMultiLineState == true`，则返回 `true`
    If rightMultiLineState Then
        ' return true
        ISqlFormatterElem_isMultiLine = True
        Exit Function
    End If

    ' 3. 检查: 如果最后一个组成元素以注释结尾，则继续
    If componentArrayIsEndsWithComment Then
        ' 如果最后一个组成元素是以注释结尾，则如果还存在边界括号，就是多行的
        ' return this.ISqlFormatterElem_hasBoundaryParenthesis()
        ISqlFormatterElem_isMultiLine = ISqlFormatterElem_hasBoundaryParenthesis
        Exit Function
    End If

    ' 4. 否则: 返回 false
    ' return false
End Function

' ==================================================
' ISqlFormatterElem -- 生成列的字符串
' ==================================================
' 生成一整行的字符串。如果本身是多行，将会使用换行符进行连接
Public Function ISqlFormatterElem_toString(ByRef config As SqlFormatterConfiguration) As String
    ' 1. 执行: 生成条件的多行字符串集合，保存到 `IPrimitiveArrayRef<String> arrRef`
    Dim arrRef As IPrimitiveArrayRef
    Set arrRef = doCreateMultiLineArray(config)

    ' 2. 处理单行的情况
    ' 2.1. 检查: 如果是单行的: `ISqlFormatterElem_isMultiLine() == false`，则继续
    If ISqlFormatterElem_isMultiLine = False Then
        ' 2.2. 返回 `arrRef` 的第一行
        ISqlFormatterElem_toString = arrRef.Item(0)
        Exit Function
    End If

    ' 3. 处理多行的情况
    ' 3.1. 使用换行符连接 `arrRef`，并返回连接结果
    ISqlFormatterElem_toString = UtilsArrayRef.reducePrimitiveArrayRefToStr(arrRef, config.lineBreak)
End Function

' 生成多行字符串
' 如果只有一行，则返回的数组引用中将会只有一个
' 并且不会在开头附加前缀空格
'
' @return IPrimitiveArrayRef<String>
Public Function ISqlFormatterElem_toStringArray(ByRef config As SqlFormatterConfiguration) As IPrimitiveArrayRef
    ' 1. 执行: 生成条件的多行字符串集合，并返回执行结果
    Set ISqlFormatterElem_toStringArray = doCreateMultiLineArray(config)
End Function

' ======================================================================
' Private Function
' ======================================================================
' 检查是否需要开头的填充空格
Private Function needStartFillSpace(ByRef config As SqlFormatterConfiguration) As Boolean
    ' 1. 检查: 如果配置的属性是不需要开头的填充空格: `config.firstConditionNeedFillSpace == false`，返回 `false`
    If config.firstConditionNeedFillSpace = false Then
        ' return false
        Exit Function
    End If

    ' 2. 否则，检查: 如果当前是所属条件组中的唯一一个条件 `isOnlyOneCondition == true`，返回 `false`
    '    如果一组条件中只有一个条件，则不需要开头的填充空格
    If isOnlyOneCondition Then
        ' return false
        Exit Function
    End If

    ' 3. 否则，检查: 如果当前条件包含逻辑运算符 `logicOperatorIndex != -1`，返回 `false`
    If logicOperatorIndex <> -1 Then
        ' return false
        Exit Function
    End If

    ' 4. 否则，需要添加开头的填充空格，返回 `true`
    '    到达这里说明是: 一个条件组中包含多个条件，并且是当前条件是这个条件组中的第一个条件
    needStartFillSpace = true
End Function

'  计算条件运算符的长度
Private Function getConditionOpStrLen(ByRef config As SqlFormatterConfiguration) As Integer
    ' 1. [获取条件运算符的字符串](获取条件运算符的字符串--getConditionOpStr) 到 `String conditionOpStr`
    ' 2. 返回字符串长度: `Len(conditionOpStr)`
    getConditionOpStrLen = Len(getConditionOpStr(config))
End Function

' 获取条件运算符的字符串
Private Function getConditionOpStr(ByRef config As SqlFormatterConfiguration) As String
    ' 1. 检查: 如果条件运算符不存在 `conditionOperatorIndex == -1`，则返回空字符串 `""`
    If conditionOperatorIndex = -1 Then
        ' return ""
        Exit Function
    End If

    ' 2. 从元素数组中获取第 `conditionOperatorIndex` 个元素到 `ISqlFormatterElem co`
    Dim co As ISqlFormatterElem
    Set co = componentArray.Item(conditionOperatorIndex)

    ' 3. 返回条件运算符的字符串 `co.toString(config)`
    getConditionOpStr = co.toString(config)
End Function

' 计算当前条件内的元素所需要的基础前缀空格的数量
'     不包含属于当前条件的前缀空格
'     这里只计算基础的前缀空格数量: 边界括号产生的空格 + 逻辑运算符导致的空格
Private Function getElemBasePrefixSpaceCount(ByRef config As SqlFormatterConfiguration) As Integer
    ' 1. 初始化 `int result = 0`
    ' int result = 0 '----> 这里直接使用 getElemBasePrefixSpaceCount

    ' 2. 检查: 如果存在边界括号 `hasBoundaryParenthesis() == true`
    If ISqlFormatterElem_hasBoundaryParenthesis Then
        ' 2.1. 检查，如果是多行的--isMultiLine() == true，则 `result += config.elemNestLevelPrefixSpaceCount`
        If ISqlFormatterElem_isMultiLine Then
            getElemBasePrefixSpaceCount = getElemBasePrefixSpaceCount + config.elemNestLevelPrefixSpaceCount
        End If
    End If

    ' 3. 检查: 如果存在逻辑运算符 `logicOperatorIndex`，则 `result += 4`
    If logicOperatorIndex <> -1 Then
        getElemBasePrefixSpaceCount = getElemBasePrefixSpaceCount + 4
    End If

    ' 4. 退出处理，返回 `result`
    ' return result
End Function

' 计算条件运算符左侧的字符串长度
Private Function getConditionOpLeftStrLen(ByRef config As SqlFormatterConfiguration) As Integer
    ' ==================================================
    ' 1. 处理条件运算符左侧列元素是多行的情况
    ' ==================================================
    ' 1. 如果左侧列对象是多行的 `leftElemIsMultiLine == 2`，则继续
    If leftElemIsMultiLine = 2 Then
        ' 2. 计算当前条件内的元素所需要的基础前缀空格的数量，并返回
        '    左边元素是多行时，从条件运算符开始会主动换行，能够出现的长度就是前缀空格的数量
        getConditionOpLeftStrLen = getElemBasePrefixSpaceCount(config)
        Exit Function
    End If

    ' ==================================================
    ' 2. 处理条件运算符左侧列元素是单行的情况
    ' ==================================================
    ' 1. 生成条件运算符左侧元素的原始字符串
    createConditionOpLeftStr config
    ' 2. 退出处理，返回最后一行字符串的长度
    getConditionOpLeftStrLen = Len(cacheOriginStrArray.getLast)
End Function

' 计算条件运算符左侧元素的前缀空格长度
Private Function getConditionOpLeftElemPrefixSpaceCount(ByRef config As SqlFormatterConfiguration) As Integer
    ' ==================================================
    ' 1. 声明变量
    ' ==================================================
    ' 1. 结果长度 `int result = 0`
    ' int result = 0 '-----> 这里直接使用 getConditionOpLeftElemPrefixSpaceCount

    ' ==================================================
    ' 2. 处理开头的填充空格
    ' ==================================================
    ' 1. 检查: 如果需要开头的填充空格，则设置 `result += 4`
    If needStartFillSpace(config) Then
        getConditionOpLeftElemPrefixSpaceCount = getConditionOpLeftElemPrefixSpaceCount + 4
    End If

    ' ==================================================
    ' 3. 处理条件内元素的基础前缀空格
    ' ==================================================
    ' 1. 计算当前条件内的元素所需要的基础前缀空格的数量，并累加到 `result`
    getConditionOpLeftElemPrefixSpaceCount = getConditionOpLeftElemPrefixSpaceCount + getElemBasePrefixSpaceCount(config)

    ' ==================================================
    ' 4. 处理当前条件的前缀空格长度
    ' ==================================================
    ' 1. 累计当前条件的前缀空格长度
    getConditionOpLeftElemPrefixSpaceCount = getConditionOpLeftElemPrefixSpaceCount + prefixSpaceCount

    ' ==================================================
    ' 5. 退出处理，并返回 `result`
    ' ==================================================
    ' return result
End Function

' 计算条件运算符右侧元素的前缀空格长度
Private Function getConditionOpRightElemPrefixSpaceCount(ByRef config As SqlFormatterConfiguration) As Integer
    ' ==================================================
    ' 1. 声明变量
    ' ==================================================
    ' 1. 结果长度 `int result`
    ' int result = 0 '-----> 这里直接使用 getConditionOpRightElemPrefixSpaceCount

    ' ==================================================
    ' 2. 处理开头的填充空格
    ' ==================================================
    ' 1. 检查: 如果需要开头的填充空格，则设置 `result += 4`
    If needStartFillSpace(config) Then
        getConditionOpRightElemPrefixSpaceCount = getConditionOpRightElemPrefixSpaceCount + 4
    End If

    ' ==================================================
    ' 3. 处理条件运算符左侧的字符串长度
    ' ==================================================
    ' 1. 计算条件运算符左侧的字符串长度，结果累加到 `result`
    getConditionOpRightElemPrefixSpaceCount = getConditionOpRightElemPrefixSpaceCount + getConditionOpLeftStrLen(config)

    ' ==================================================
    ' 4. 处理对齐空格长度
    ' ==================================================
    ' 1. 累计对齐空格的长度: `result += alignmentSpaceCount`
    getConditionOpRightElemPrefixSpaceCount = getConditionOpRightElemPrefixSpaceCount + alignmentSpaceCount

    ' ==================================================
    ' 5. 处理条件运算符的长度
    ' ==================================================
    ' 1. 检查: 如果左侧列对象是单行
    If leftElemIsMultiLine = 1 Then
        ' 1.1. 计算条件运算符的长度，并累加到 `result`
        getConditionOpRightElemPrefixSpaceCount = getConditionOpRightElemPrefixSpaceCount + getConditionOpStrLen(config)
        ' 1.2. 长度额外 + 2: `result += 2`
        '    一个 `1` 表示左侧元素、条件运算符之间的空格
        '    一个 `1` 表示右侧元素、条件运算符之间的空格
        getConditionOpRightElemPrefixSpaceCount = getConditionOpRightElemPrefixSpaceCount + 2

    ' 2. 否则，检查: 如果右侧是单行
    ElseIf rightMultiLineState = False Then
        ' 1.1. 计算条件运算符的长度，并累加到 `result`
        getConditionOpRightElemPrefixSpaceCount = getConditionOpRightElemPrefixSpaceCount + getConditionOpStrLen(config)
        ' 1.2. 长度额外 + 1: `result += 1`
        '    一个 `1` 表示右侧元素、条件运算符之间的空格
        getConditionOpRightElemPrefixSpaceCount = getConditionOpRightElemPrefixSpaceCount + 1
    End If
    ' 3. 否则，如果右侧是多行的，则不需要处理条件运算符

    ' ==================================================
    ' 6. 处理当前条件的前缀空格长度
    ' ==================================================
    ' 1. 累计当前条件的前缀空格长度: `result += prefixSpaceCount`
    getConditionOpRightElemPrefixSpaceCount = getConditionOpRightElemPrefixSpaceCount + prefixSpaceCount

    ' ==================================================
    ' 8. 退出处理，并返回 `result`
    ' ==================================================
    ' return result
End Function

' 生成条件的多行字符串集合
' @return IPrimitiveArrayRef<String>
Private Function doCreateMultiLineArray(ByRef config As SqlFormatterConfiguration) As IPrimitiveArrayRef
    ' 1. 生成条件运算符左侧元素的字符串集合
    createConditionOpLeftStr config
    ' 2. 生成条件运算符及其右侧元素的字符串集合
    createConditionOpAndRightStr config

    ' 3. 处理开头的填充空格
    ' 3.1. 检查: 如果需要开头的填充空格
    If needStartFillSpace(config) Then
        ' 3.3 遍历 `cacheOriginStrArray` 中的每一行，并添加 4 个前缀空格
        Dim i As Long
        For i = 0 To cacheOriginStrArray.MaxIndex
            cacheOriginStrArray.setVal i, "    " & cacheOriginStrArray.Item(i)
        Next
    End If

    ' 4. 暂存缓存集合的结果 `result = cacheOriginStrArray`
    Set doCreateMultiLineArray = cacheOriginStrArray
    ' 5. 清除缓存: `cacheOriginStrArray = null`
    Set cacheOriginStrArray = Nothing
    ' 6. 返回 `result`
    ' return result
End Function

' 生成条件运算符左侧元素的字符串集合
Private Sub createConditionOpLeftStr(ByRef config As SqlFormatterConfiguration)
    ' ==================================================
    ' 1. 检查: 如果结果集合的缓存已经存在了 `cacheOriginStrArray != null`，则立刻结束
    ' ==================================================
    If Not cacheOriginStrArray Is Nothing Then
        ' return
        Exit Sub
    End If

    ' ==================================================
    ' 2. 声明变量
    ' ==================================================
    ' 1. 行字符串 `String lineStr`
    Dim lineStr As String
    ' 2. 前缀空格 `String prefixSpace = ""`
    Dim prefixSpace As String
    ' 3. 需要连接的元素的数组引用切片: `IObjArrayRef<ISqlFormatterElem> componentsSlice`
    Dim componentsSlice As IObjArrayRef
    ' 4. 当前条件是否是多行的: `boolean isMultiCondition`
    Dim isMultiCondition As Boolean
    ' 5. 元素对象 `ISqlFormatterElem component`
    Dim component As ISqlFormatterElem
    ' 6. 元素的字符串 `String tempStr`
    Dim tempStr As String
    ' 7. 连接的起始索引 `long startIndex = 0`
    Dim startIndex As long
    startIndex = 0
    '  8. 截取时使用的结束索引 `long endIndex`
    Dim endIndex As Long

    ' ==================================================
    ' 3. 初始化
    ' ==================================================
    ' 1. 当前条件是否是多行的
    isMultiCondition = ISqlFormatterElem_isMultiLine

    ' 2. 缓存集合
    ' 2.1. 检查: 如果当前条件是多行的 `isMultiCondition == true`，则创建
    If isMultiCondition Then
        Set cacheOriginStrArray = UtilsArrayRef.createRealPrimitiveArrayRef(8)

    ' 2.2. 否则，创建一个长度为 1 的数组引用
    Else
        Set cacheOriginStrArray = UtilsArrayRef.createRealPrimitiveArrayRef(1)
    End IF

    ' ==================================================
    ' 4. 处理左边界括号
    ' ==================================================
    ' 1. 检查，如果存在边界括号 `hasBoundaryParenthesis() == true`，则继续
    If ISqlFormatterElem_hasBoundaryParenthesis Then
        ' 2. 检查: 如果条件是多行的: `isMultiCondition == true`
        If isMultiCondition Then
            ' 2.1. 设置前缀空格 `prefixSpace += config.elemNestLevelPrefixSpace`
            '      即括号内层的多行内容需要再额外附加一个单位的前缀空格
            prefixSpace = prefixSpace & config.elemNestLevelPrefixSpace

            ' 2.1. 检查: 如果存在左边界括号 `leftParenthesisCount > 0` ，则将 `等量的括号` 保存到 `cacheOriginStrArray`
            If leftParenthesisCount > 0 Then
                ' 2.2.1. 生成等量的左括号，并保存到 `lineStr`
                lineStr = UtilsString.repeatLeftParenthesis(leftParenthesisCount)

                ' 2.2.2. 尝试吸收后面出现的同行注释
                ' 2.2.2.1. 检查: 如果组成元素数量 > 0，则继续:
                If componentArray.Count > 0 Then
                    ' 2.2.2.2. 获取第一个元素，保存到 `component`
                    Set component = componentArray.Item(0)
                    ' 2.2.2.3. 检查: 如果元素类型是同行注释，则继续: `component.isShareLineComment() == true`
                    If component.isShareLineComment Then
                        ' 2.2.2.4. 连接字符串 `lineStr += " " + component.toString(config)`
                        lineStr = lineStr & " " & component.toString(config)
                        ' 2.2.2.5. 设置 `startIndex = 1`
                        startIndex = 1
                    End If
                End If

                ' 2.2.3. 将 `lineStr` 保存到 `cacheOriginStrArray`
                cacheOriginStrArray.Add lineStr

                ' 2.2.4. 设置 `lineStr` 为空字符串
                lineStr = ""
            End If

        ' 3. 否则 (条件是单行的)
        Else
            ' 3.1. 检查: 如果存在左边界括号 `leftParenthesisCount > 0` ，则设置 `lineStr += 等量的左括号`
            If leftParenthesisCount > 0 Then
                lineStr = lineStr & UtilsString.repeatLeftParenthesis(leftParenthesisCount)
            End If
        End If
    End If

    ' ==================================================
    ' 5. 处理逻辑运算符及其之前的元素
    ' ==================================================
    ' 1. 检查: 如果逻辑运算符存在 `logicOperatorIndex != -1`，则继续
    If logicOperatorIndex <> -1 Then
        ' 2. 检查: 如果逻辑运算符不是第一个元素 `logicOperatorIndex != 0` ，则处理逻辑运算符之前的元素
        If logicOperatorIndex <> 0 Then
            ' 2.1. 生成需要参与连接的元素的引用
            '    这里截取逻辑运算符前面的所有元素
            Set componentsSlice = componentArray.slice(startIndex, logicOperatorIndex)
            ' 2.2.[连接 componentsSlice 中的元素
            SqlFormatterHelper.fullAndJoinArrayElem _
                config, _
                componentsSlice, _
                cacheOriginStrArray, _
                prefixSpace, _
                lineStr, _
                ""
            ' 2.3. 从 `cacheOriginStrArray` 中弹出最后一行的内容，保存到 `lineStr`
            lineStr = cacheOriginStrArray.pollLast
        End If

        ' 3. 处理逻辑运算符
        ' 3.1. 获取逻辑运算符元素
        Set component = componentArray.Item(logicOperatorIndex)
        ' 3.2. 生成逻辑运算符的单行字符串
        tempStr = component.toString(config)
        ' 3.3. 连接 `lineStr` + `tempStr`, 结果保存到 `lineStr`
        lineStr = SqlFormatterHelper.joinTwoElemStr(lineStr, tempStr)
        ' 3.4. 在后面附加空格
        ' 3.4.1. 检查: 如果逻辑运算符后面还有元素 `logicOperatorIndex < componentArray.MaxIndex`，则继续
        If logicOperatorIndex < componentArray.MaxIndex Then
            ' 3.4.2. 获取 `componentArray` 的第 `logicOperatorIndex + 1` 个元素到 `component`
            Set component = componentArray.Item(logicOperatorIndex + 1)
            ' 3.4.3. 检查: 如果 `componentArray` 第 `logicOperatorIndex + 1` 个元素是同行注释
            If component.isShareLineComment Then
                ' 3.4.3.1. 检查: 如果条件运算符的长度是 2 (是 `or`)，则需要在后面连接 1 个空格 `lineStr += " "`
                If Len(tempStr) = 2 Then
                    lineStr = lineStr & " "
                End If

            ' 3.4.4. 否则，检查: 如果  `component` 的类型不是单行注释
            ElseIf Not component.isSingleLineComment Then
                ' 3.4.3.1. 检查: 如果条件运算符的长度是 2 (是 `or`)，则需要在后面连接 2 个空格 `lineStr += "  "`
                If Len(tempStr) = 2 Then
                    lineStr = lineStr & "  "

                ' 3.4.3.2. 否则，需要在后面连接 1 个空格 `lineStr += " "`
                Else
                    lineStr = lineStr & " "
                End If
            End If
        End If
    End If

    ' ==================================================
    ' 6. 处理条件运算符左侧的元素
    ' ==================================================
    ' 1. 生成需要参与连接的元素的引用
    ' 1.1. 起始索引
    ' 1.1.1. 如果存在逻辑运算符，设置 `startIndex = logicOperatorIndex + 1`
    If logicOperatorIndex <> -1 Then
        startIndex = logicOperatorIndex + 1
    End If
    ' 1.1.2. 否则，直接使用 `startIndex`
    ' noop

    ' 1.2. 结束索引(截取时，不包含这个索引)
    ' 1.2.1. 如果存在条件运算符，设置为 `endIndex = conditionOperatorIndex`
    If conditionOperatorIndex <> -1 Then
        endIndex = conditionOperatorIndex

    ' 1.2.2. 否则，设置为 `endIndex = componentArray.Count`
    Else
        endIndex = componentArray.Count
    End If
    ' 1.3. 截取: `componentsSlice = componentArray[startIndex, endIndex)`
    Set componentsSlice = componentArray.slice(startIndex, endIndex)

    ' 2. 计算连接字符串时的 `extraSpaceAfterFirstSave`
    ' 2.1. 检查: 如果逻辑运算符存在 `logicOperatorIndex != -1`，则设置为长度为 4 的空格
    If logicOperatorIndex <> -1 Then
        tempStr = "    "

    ' 2.2. 设置为空字符串: `tempStr = ""`
    Else
        tempStr = ""
    End If

    ' 3. 连接 componentsSlice 中的元素
    SqlFormatterHelper.fullAndJoinArrayElem _
        config, _
        componentsSlice, _
        cacheOriginStrArray, _
        prefixSpace, _
        lineStr, _
        tempStr
End Sub

' 生成条件运算符及其右侧元素的字符串集合
Private Sub createConditionOpAndRightStr(ByRef config As SqlFormatterConfiguration)
    ' ==================================================
    ' 1. 快速结束
    ' ==================================================
    ' 1. 提前声明变量: 行字符串 `String lineStr`
    Dim lineStr As String
    ' 2. 检查: 如果条件运算符不存在 `conditionOperatorIndex == -1`，则立刻结束
    If conditionOperatorIndex = -1 Then
        ' 3. 处理右边界括号
        ' 3.1. 检查，如果存在右边界括号 `rightParenthesisCount > 0`，则继续
        If rightParenthesisCount > 0 Then
            ' 3.2. 检查: 如果条件是多行的: `isMultiLine() == true`，则将 `等量的括号` 保存到 `cacheOriginStrArray`
            If ISqlFormatterElem_isMultiLine Then
                cacheOriginStrArray.Add UtilsString.repeatRightParenthesis(rightParenthesisCount)

            ' .3. 否则 (条件是单行的)
            Else
                ' 3.3.1. 从 `cacheOriginStrArray` 中获取第一行到 `lineStr`: `Item(0)`
                lineStr = cacheOriginStrArray.Item(0)
                ' 3.3.2. 设置 `lineStr += 等量的右括号`
                lineStr = lineStr & UtilsString.repeatRightParenthesis(rightParenthesisCount)
                ' 3.3.3. 将 `lineStr` 写回 `cacheOriginStrArray` 的第一行: `setVal(0, lineStr)`
                cacheOriginStrArray.setVal 0, lineStr
            End If
        End If

        ' 4. 退出处理
        ' return
        Exit Sub
    End If

    ' ==================================================
    ' 2. 声明变量
    ' ==================================================
    ' 1. 条件运算符前的空格 `String startSpace`
    Dim startSpace As String
    ' 2. 需要连接的元素的数组引用切片: `IObjArrayRef<ISqlFormatterElem> componentsSlice`
    Dim componentsSlice As IObjArrayRef
    ' 3. 右侧元素的起始前缀空格 `String rightElemStartPrefixSpace`
    '    作为连接右侧元素时的参数
    Dim rightElemStartPrefixSpace As String
    ' 4. 右侧元素连接时，在换行后需要额外附加的前缀空格 `String rightElemExtraSpaceAfterFirstSave`
    '    作为连接右侧元素时的参数
    Dim rightElemExtraSpaceAfterFirstSave As String

    ' 5. 右侧元素的起始索引 `long rightElemStartIndex = conditionOperatorIndex + 1`
    '    这里是为了处理条件运算符后面可能存在的同行注释后，能够定位右侧的起始元素
    Dim rightElemStartIndex As Long
    rightElemStartIndex = conditionOperatorIndex + 1

    ' 6. 组成元素 `ISqlFormatterElem elem`
    Dim elem As ISqlFormatterElem

    ' ==================================================
    ' 3. 处理左侧不换行的情况
    ' ==================================================
    ' 1. 检查: 左侧列元素是单行的，则不需要换行，继续: `leftElemIsMultiLine == 1`
    If leftElemIsMultiLine = 1 Then
        ' 2. 从 `cacheOriginStrArray` 中弹出最后一行到 `lineStr`
        lineStr = cacheOriginStrArray.pollLast

        ' 3. 生成 `alignmentSpaceCount + 1` 个空格，并保存到 `startSpace`
        startSpace = startSpace & space(alignmentSpaceCount + 1)

        ' 4. 连接空格: `lineStr += startSpace`
        lineStr = lineStr + startSpace

        ' 5. 连接条件运算符
        lineStr = lineStr + getConditionOpStr(config)

        ' 6. 生成连接右侧元素时需要使用的前缀空格 `startSpace = space(Len(lineStr) + 1)`
        startSpace = space(Len(lineStr) + 1)

    ' ==================================================
    ' 4. 处理左侧换行的情况 (左侧全是注释或者左侧没有元素的情况也在这里处理)
    ' ==================================================
    ' 1. 否则 (接 3 的判断)，继续
    Else
        ' 2. 计算当前条件内的元素所需要的基础前缀空格的数量，并生成等量的空格，保存到 `startSpace`
        startSpace = space(getElemBasePrefixSpaceCount(config))

        ' 3. 设置 `lineStr = startSpace`
        lineStr = startSpace

        ' 4. 连接条件运算符: `lineStr += 条件运算符字符串`
        lineStr = lineStr + getConditionOpStr(config)

    End If

    ' ==================================================
    ' 5. 处理条件运算符后面可能存在的注释 (同行注释、单行注释都要处理)
    ' ==================================================
    ' 1. 检查: 如果条件运算符后面还有元素，则继续: `conditionOperatorIndex < componentArray.MaxIndex`
    If conditionOperatorIndex < componentArray.MaxIndex Then
        ' 2. 从 `componentArray` 获取第 `conditionOperatorIndex + 1` 个元素到 `elem`
        Set elem = componentArray.Item(conditionOperatorIndex + 1)
        ' 3. 检查: 如果 `elem` 是同行注释，则继续: `isShareLineComment() == true`
        With elem ' -- 在这里加速
            If .isShareLineComment Then
                ' 3.1. 连接元素: `lineStr += " " + elem.toString(config)`
                lineStr = lineStr & " " & .toString(config)
                ' 3.2. 将 `lineStr` 保存到 `cacheOriginStrArray`
                cacheOriginStrArray.Add lineStr
                ' 3.3. 重置 `lineStr = ""`
                lineStr = ""
                ' 3.4. 右侧元素的起始索引向后移动 `rightElemStartIndex++`
                rightElemStartIndex = rightElemStartIndex + 1

            ' 4. 否则，检查: 如果 `elem` 是单行注释，则继续: `isSingleLineComment() == true`
            ElseIf .isSingleLineComment Then
                ' 4.1. 将 `lineStr` 保存到 `cacheOriginStrArray`
                cacheOriginStrArray.Add lineStr
                ' 4.2. 重置 `lineStr = ""`
                lineStr = ""
                ' 4.3. 将 `startSpace + elem.toString(config)` 保存到 `cacheOriginStrArray`
                cacheOriginStrArray.Add startSpace & .toString(config)
                ' 4.4. 右侧元素的起始索引向后移动 `rightElemStartIndex++`
                rightElemStartIndex = rightElemStartIndex + 1
            End If
        End With
    End If

    ' ==================================================
    ' 6. 处理需要提前保存的情况
    ' ==================================================
    ' 1. 检查: 如果 `lineStr != ""` (还没有保存过)，则继续
    If lineStr <> "" Then
        ' 2. 检查: 如果左侧列元素是多行的 `leftElemIsMultiLine == 2` + 右侧元素是多行的情况 `rightMultiLineState == true`，则继续
        If leftElemIsMultiLine = 2 And rightMultiLineState  Then
            ' 3. 将 `lineStr` 提前保存到 `cacheOriginStrArray`
            cacheOriginStrArray.Add lineStr
            ' 4. 重置 `lineStr = ""`
            lineStr = ""
        End If
    End If

    ' ==================================================
    ' 7. 设置连接右侧元素时需要使用到的前缀空格
    ' ==================================================
    ' 1. 检查: 如果 `lineStr == ""` (这里处理条件运算符后有同注释的情况，或者被提前保存的情况)
    If lineStr = "" Then
        ' 1.1. 设置 `rightElemStartPrefixSpace = startSpace`
        rightElemStartPrefixSpace = startSpace
        ' 1.2. 设置 `rightElemExtraSpaceAfterFirstSave = ""`
        rightElemExtraSpaceAfterFirstSave = ""

    ' 2. 否则
    Else
        ' 2.1. 设置 `rightElemStartPrefixSpace = ""`
        '      只要是 lineStr 没有保存过，则前缀空格一定时已经连接到 lineStr 前面的状态（无论左侧元素是什么情况），
        '      所以这里设置为空，防止后面执行连接右侧元素处理时在前面重复添加前缀空格
        rightElemStartPrefixSpace = ""
        ' 2.2. 设置 `rightElemExtraSpaceAfterFirstSave = startSpace`
        rightElemExtraSpaceAfterFirstSave = startSpace
    End If

    ' ==================================================
    ' 8. 处理条件运算符右侧的元素
    ' ==================================================
    ' 1. 生成需要参与连接的元素的引用
    Set componentsSlice = componentArray.slice(rightElemStartIndex, componentArray.Count)
    ' 2. 连接 componentsSlice 中的元素
    SqlFormatterHelper.fullAndJoinArrayElem _
        config, _
        componentsSlice, _
        cacheOriginStrArray, _
        rightElemStartPrefixSpace, _
        lineStr, _
        rightElemExtraSpaceAfterFirstSave

    ' ==================================================
    ' 9. 处理右边界括号
    ' ==================================================
    ' 1. 检查，如果存在右边界括号 `rightParenthesisCount > 0`，则继续
    If rightParenthesisCount > 0 Then
        ' 2. 检查: 如果条件是多行的: `isMultiLine() == true`，则将 `等量的括号` 保存到 `cacheOriginStrArray`
        If ISqlFormatterElem_isMultiLine Then
            cacheOriginStrArray.Add UtilsString.repeatRightParenthesis(rightParenthesisCount)

        ' 3. 否则 (条件是单行的)
        Else
            ' 3.1. 从 `cacheOriginStrArray` 中获取第一行到 `lineStr`
            lineStr = cacheOriginStrArray.Item(0)
            ' 3.2. 设置 `lineStr += 等量的右括号`
            lineStr = lineStr + UtilsString.repeatRightParenthesis(rightParenthesisCount)
            ' 3.3. 将 `lineStr` 写回 `cacheOriginStrArray` 的第一行
            cacheOriginStrArray.setVal 0, lineStr
        End If
    End If
End Sub

' 从指定范围内的元素中获取条件组
' @return IObjArrayRef<IObjArrayRef<ISqlFormatterAlignmentElem>>
Private Function doGetConditionGroupFromComponents( _
    ByRef startIndex As Long, ByRef endIndex As long) As IObjArrayRef
    ' ==================================================
    ' 1. 声明变量
    ' ==================================================
    ' 1. 遍历起始索引 `long i`
    Dim i As Long
    ' 2. 元素对象 `ISqlFormatterElem component`
    Dim component As ISqlFormatterElem
    ' 3. 临时分组 `IObjArrayRef<IObjArrayRef<ISqlFormatterAlignmentElem>> groups`
    Dim groups As IObjArrayRef
    ' 4. 结果集合: `IObjArrayRef<IObjArrayRef<ISqlFormatterAlignmentElem>> result`
    Dim result As IObjArrayRef

    ' ==================================================
    ' 2. 遍历元素
    ' ==================================================
    ' 1. 从 `i = startIndex` 开始到 `endIndex`，遍历 `componentArray`
    For i = startIndex To endIndex
        ' 2. 获取第 i 个组成元素 `component`
        Set component = componentArray.Item(i)
        ' 3. 获取这个元素的条件组，保存到 `groups`
        Set groups = component.getAlignmentElemGroups
        ' 4. 检查: 如果 `groups` 不是空，则继续
        If Not groups Is Nothing Then
            ' 5. 检查: 如果结果集合还没有创建 `result = null`，则创建 `UtilsArrayRef.createRealObjArrayRef<IObjArrayRef<ISqlFormatterAlignmentElem>>(8)`
            If result Is Nothing Then
                Set result = UtilsArrayRef.createRealObjArrayRef(8)
            End If
            ' 6. 将 `groups` 合并到 `result`
            result.mergeArrRef groups
        End If
        ' 7. 从 2 开始下一轮遍历
    Next

    ' ==================================================
    ' 3. 退出处理，返回 `result`
    ' ==================================================
    ' return result;
    Set doGetConditionGroupFromComponents = result
End Function
